#coding=utf-8
import numpy as np

def svm_loss_native(W, X, y, reg):
  '''
  svm_loss的朴素实现
  输入的维度是D，有C个分类类别，并且我们在有N个例子的batch上进行操作
    输入:
    - W: 一个numpy array，形状是(D, C)，代表权重
    - X: 一个形状为(N, D)为numpy array，代表输入数据
    - y: 一个形状为(N,)的numpy array，代表类别标签
    - reg: (float)正则化参数
    f返回:
    - 一个浮点数代表Loss
    - 和W形状一样的梯度
  '''
  dW = np.zeros_like(W) #初始化权值矩阵
  num_classes = W.shape[1]
  num_train = X.shape[0]
  loss = 0.0
  for i in xrange(num_train):
    scores = X[i].dot(W)
    correct_class_score = scores[y[i]]
    for j in xrange(num_classes):
      if j == y[i]:
        continue
      margin = scores[j] - correct_class_score + 1 #note delta = 1
      if margin > 0:
        loss += margin
        dW[:, j] += X[i].T
        dW[:, y[i]] += -X[i].T
  loss /= num_train
  dW /= num_train
  loss += 0.5 * reg * np.sum(W * W)
  dW += reg * W
  return loss, dW

def svm_loss_vectorized(W, X, y, reg):
  loss = 0.0
  dW = np.zeros_like(W)
  num_classes = W.shape[1]
  num_train = X.shape[0]
  scores = X.dot(W)
  correct_class_scores = scores[range(num_train), list(y)].reshape(-1, 1) #[N, 1]
  margins = np.maximum(0, scores - correct_class_scores + 1)
  margins[range(num_train), list(y)] = 0
  loss = np.sum(margins) / num_train + 0.5 * reg * np.sum(W * W)

  coffe_mat = np.zeros((num_train, num_classes))
  coffe_mat[margins > 0] = 1
  coffe_mat[range(num_train), list(y)] = 0
  coffe_mat[range(num_train), list(y)] = -np.sum(coffe_mat, axis=1) #按行求和

  dW = (X.T).dot(coffe_mat)
  dW = dW/num_train + reg*W
  return loss, dW





